%PC1-PC10 + accuracy + PCA heatmap + t-SNE(PC1-5) + UMAP(PC1-5)
%% Load Data
clear; clc;
filename = 'Z_all.csv';
opts = detectImportOptions(filename);
opts.DataLines = 2; % Skip header row (timestamps)
raw = readmatrix(filename, opts);
clear labels; % Ensure no function conflict
labels = [zeros(277,1); ones(171,1)]; % 0: non-USV, 1: USV
X = raw(:, 2:end); % Remove ID column

% Define time axis (in seconds)
time = -1.975:0.025:0.5;

%% PCA
[coeff, score, latent, ~, explained] = pca(X);

% Save eigenvalue table
T = table((1:10)', latent(1:10), explained(1:10), coeff(:,1:10)', 'VariableNames', {'PC', 'Eigenvalue', 'ExplainedVariance', 'TracePattern'});
writetable(T, 'PCA_Eigenvalue_Table.xlsx');
plot(time, coeff(:,1:2)) % 例：畫出前2個PC的trace pattern
legend('PC1','PC2');
xlabel('Time (s)');
ylabel('Loading');
saveas(gcf, 'Figure1_TracePattern_PCAloadingvsTime.png');

% Cumulative plot
figure;
plot(cumsum(explained), '-o');
xlabel('Number of Principal Components'); ylabel('Cumulative Variance Explained (%)');
title('Cumulative Variance Explained');
saveas(gcf, 'Figure2_CumulativeVariance.png');

% PC1 and PC2 trace patterns
figure;
subplot(1,2,1);
plot(time, coeff(:,1), 'LineWidth', 2); title('PC1 Trace Pattern'); xlabel('Time (s)'); ylabel('Weight');
subplot(1,2,2);
plot(time, coeff(:,2), 'LineWidth', 2); title('PC2 Trace Pattern'); xlabel('Time (s)'); ylabel('Weight');
saveas(gcf, 'Figure3_PC_TracePatterns.png');

%% PC1 vs PC2 Projection with Labels
figure;
labels_categorical = categorical(labels(:));
if size(score,1) == length(labels_categorical)
    gscatter(score(:,1), score(:,2), labels_categorical, 'rb', 'ox');
    title('PCA Projection (PC1 vs PC2)'); xlabel('PC1'); ylabel('PC2'); legend('non-USV','USV');
    saveas(gcf, 'Figure4_PC1_PC2_Projection.png');
else
    warning('Mismatch between number of rows in score and length of labels. Skipping gscatter plot.');
end
figure;
labels_categorical = categorical(labels(:));
if size(score,1) == length(labels_categorical)
    lda = fitcdiscr(score(:,1:2), labels);  % 使用 PC1 + PC2 投影作為特徵
    [lda_pred, lda_score] = predict(lda, score(:,1:2));
    gscatter(score(:,1), score(:,2), labels_categorical, 'rb', 'ox');
    hold on;
    x1range = linspace(min(score(:,1)), max(score(:,1)), 200);
    x2range = linspace(min(score(:,2)), max(score(:,2)), 200);
    [X1, X2] = meshgrid(x1range, x2range);
    XGrid = [X1(:), X2(:)];
    lda_grid_pred = predict(lda, XGrid);
    Z = reshape(lda_grid_pred, size(X1));
    contour(X1, X2, Z, [0.5 0.5], 'k', 'LineWidth', 2);
    title('PCA + LDA Classification (PC1 vs PC2)');
    xlabel('PC1'); ylabel('PC2');
    legend('non-USV','USV','LDA Decision Boundary');
    hold off;
    saveas(gcf, 'Figure5_PCA_LDA_Projection_with_Boundary.png');
else
    warning('Mismatch between number of rows in score and length of labels. Skipping gscatter plot.');
end

%% Logistic Regression with First 10 PCs
scores_fixed = score(:,1:10);
mdl_fixed = fitglm(scores_fixed, labels, 'Distribution', 'binomial');
[pred_probs_fixed,~] = predict(mdl_fixed, scores_fixed);
[Xroc_fixed,Yroc_fixed,~,auc_fixed] = perfcurve(labels, pred_probs_fixed, 1);
figure;
plot(Xroc_fixed, Yroc_fixed, 'LineWidth', 2); grid on;
title(sprintf('ROC Curve (Logistic Regression, PC1-10), AUC=%.2f', auc_fixed));
xlabel('False Positive Rate'); ylabel('True Positive Rate');
saveas(gcf, 'Figure6_ROC_Logistic_PC1to10.png');

% === NEW: Most Predictive PC Trace Pattern (by logistic regression weights) ===
logit_weights = mdl_fixed.Coefficients.Estimate(2:end);  % exclude intercept
[~, top_pc_idx] = maxk(abs(logit_weights), 2);

figure;
plot(time, coeff(:,top_pc_idx(1)), 'LineWidth', 2); hold on;
plot(time, coeff(:,top_pc_idx(2)), 'LineWidth', 2);
legend(sprintf('PC%d', top_pc_idx(1)), sprintf('PC%d', top_pc_idx(2)));
xline(0, '--k', 'LineWidth', 1.5);  % USV onset
xline(-1, '--', 'Color', [0.5 0.5 0.5]);
xline(-0.5, '--', 'Color', [0.5 0.5 0.5]);
xlabel('Time (s)'); ylabel('Weight');
title('Top 2 Predictive PC Trace Patterns (Logistic Regression)');
saveas(gcf, 'Figure7__Top2_Predictive_TracePatterns_LogReg.png');

% === NEW: Reconstruct representative trace pattern (in fluorescence scale) ===
usv_score = score(labels==1, :);
usv_mean_scores = mean(usv_score(:, top_pc_idx), 1);  % 1x2 vector
reconstructed_trace = coeff(:,top_pc_idx) * usv_mean_scores';  % weighted sum

figure;
plot(time, reconstructed_trace, 'LineWidth', 2);
xline(0, '--k', 'LineWidth', 1.5);
title('Reconstructed Trace Pattern (USV Mean, Top 2 PCs)');
xlabel('Time (s)'); ylabel('Reconstructed Fluorescence Signal');
saveas(gcf, 'Figure8_Reconstructed_Trace_Top2PC_USVonly.png');

% === NEW: Reconstructed trace from individual top PCs ===
ind_trace1 = coeff(:,top_pc_idx(1)) * usv_mean_scores(1);
ind_trace2 = coeff(:,top_pc_idx(2)) * usv_mean_scores(2);
figure;
plot(time, ind_trace1, 'b-', 'LineWidth', 2); hold on;
plot(time, ind_trace2, 'r-', 'LineWidth', 2);
legend(sprintf('PC%d only', top_pc_idx(1)), sprintf('PC%d only', top_pc_idx(2)));
xline(0, '--k', 'LineWidth', 1.5);
title('Individual PC Reconstructed Trace Patterns (USV)');
xlabel('Time (s)'); ylabel('Partial Reconstructed Fluorescence');
saveas(gcf, 'Figure9_Individual_Reconstructed_Trace_Top2PC_USVonly.png');

%% LDA Using First 10 PCs with Cross-validation
cv = cvpartition(labels, 'KFold', 10);
lda = fitcdiscr(scores_fixed, labels, 'CVPartition', cv);
lda_loss = kfoldLoss(lda);

% Get average LDA projection over folds (not simple due to CV, so fallback to full data projection)
lda_full = fitcdiscr(scores_fixed, labels);
lda_proj = scores_fixed * lda_full.Coeffs(1,2).Linear + lda_full.Coeffs(1,2).Const;
figure;
histogram(lda_proj(labels==0), 'Normalization','probability', 'FaceColor','r'); hold on;
histogram(lda_proj(labels==1), 'Normalization','probability', 'FaceColor','b');
title(sprintf('LDA Projection using PC1-10 (Accuracy: %.2f%%)', 100*(1-lda_loss)));
legend('non-USV','USV'); xlabel('LDA Projection');
saveas(gcf, 'Figure10_LDA_Projection_PC1to10.png');

%% LDA Projection using KDE Curve
% Get LDA projection again (if not already in workspace)
scores_fixed = score(:,1:10);
lda_full = fitcdiscr(scores_fixed, labels);
lda_proj = scores_fixed * lda_full.Coeffs(1,2).Linear + lda_full.Coeffs(1,2).Const;

% Compute KDE for both groups
[usv_kde, usv_x] = ksdensity(lda_proj(labels==1));
[nonusv_kde, nonusv_x] = ksdensity(lda_proj(labels==0));

% Plot KDE
figure;
plot(nonusv_x, nonusv_kde, 'r-', 'LineWidth', 2); hold on;
plot(usv_x, usv_kde, 'b-', 'LineWidth', 2);
xlabel('LDA Projection Score'); ylabel('Density');
title(sprintf('LDA Projection using PC1–10 (KDE), Accuracy: %.2f%%', 100*(1-lda_loss)));
legend('non-USV','USV');
grid on;
saveas(gcf, 'Figure5_LDA_KDE_PC1to10.png');

%% LDA Projection Histogram (Normalized per Group)
% 計算 LDA 投影值（如果還沒在 workspace 中）
scores_fixed = score(:,1:10);
lda_full = fitcdiscr(scores_fixed, labels);
lda_proj = scores_fixed * lda_full.Coeffs(1,2).Linear + lda_full.Coeffs(1,2).Const;

% 定義 bin 範圍
edges = linspace(min(lda_proj), max(lda_proj), 30);

% 計算每組的直方圖（以各組內比例標準化）
usv_hist = histcounts(lda_proj(labels==1), edges, 'Normalization', 'probability');
nonusv_hist = histcounts(lda_proj(labels==0), edges, 'Normalization', 'probability');

% 計算 bin 中心位置
bin_centers = edges(1:end-1) + diff(edges)/2;

% 畫圖
figure;
bar(bin_centers, nonusv_hist, 'r', 'FaceAlpha', 0.6, 'BarWidth', 1); hold on;
bar(bin_centers, usv_hist, 'b', 'FaceAlpha', 0.6, 'BarWidth', 1);
xlabel('LDA Projection Score'); ylabel('Proportion within Group');
title(sprintf('LDA Projection using PC1–10 (Normalized), Accuracy: %.2f%%', 100*(1-lda_loss)));
legend('non-USV', 'USV');
grid on;
saveas(gcf, 'Figure5_LDA_Hist_PerGroupNormalized.png');


%% Statistical Tests
% Mann-Whitney U test (ranksum)
[p_mw, ~] = ranksum(lda_proj(labels==1), lda_proj(labels==0));

% Permutation Test
n_perm = 10000;
m1 = mean(lda_proj(labels==1));
m0 = mean(lda_proj(labels==0));
s1 = std(lda_proj(labels==1));
s0 = std(lda_proj(labels==0));
s_pooled = sqrt((s1^2 + s0^2)/2);
cohen_d = (m1 - m0)/s_pooled;
real_diff = abs(m1 - m0);
combined = lda_proj;
perm_diffs = zeros(n_perm,1);
for i = 1:n_perm
    perm_labels = labels(randperm(length(labels)));
    pm1 = mean(lda_proj(perm_labels==1));
    pm0 = mean(lda_proj(perm_labels==0));
    perm_diffs(i) = abs(pm1 - pm0);
end
p_perm = mean(perm_diffs >= real_diff);

% Display results
fprintf('Cohen''s d: %.3f\n', cohen_d);
fprintf('Mann-Whitney U p-value: %.5f\n', p_mw);
fprintf('Permutation Test p-value: %.5f\n', p_perm);
fprintf('LDA Cross-Validated Accuracy: %.2f%%\n', 100*(1 - lda_loss));

%% PCA Correlation Heatmap (Group First, Then Sorted by LDA)
figure;

% === Step 1: 計算 LDA 投影值（假設你已有前10個PC）===
scores_fixed = score(:,1:10);                     % 使用 PC1–PC10
lda_full = fitcdiscr(scores_fixed, labels);       % 全資料訓練 LDA 模型
lda_proj = scores_fixed * lda_full.Coeffs(1,2).Linear + lda_full.Coeffs(1,2).Const;

% === Step 2: 先依 label 分群，再各自以 LDA 投影排序 ===
% 將 USV (label=1) 放在前，non-USV (label=0) 放後
group1_idx = find(labels == 1);
group0_idx = find(labels == 0);

% 各組依照投影值排序
[~, usv_sort] = sort(lda_proj(group1_idx));
[~, nonusv_sort] = sort(lda_proj(group0_idx));

% 合併排序後的索引
final_idx = [group1_idx(usv_sort); group0_idx(nonusv_sort)];

% 重新排列資料與標籤
X_sorted = X(final_idx, :);
labels_sorted = labels(final_idx);
lda_proj_sorted = lda_proj(final_idx);

% === Step 3: 計算 correlation matrix ===
corr_matrix = corr(X_sorted');

% === Step 4: 畫 heatmap ===
imagesc(corr_matrix);
colormap(turbo);
caxis([-1 1]);
colorbar;
title('PCA Correlation Heatmap (USV → non-USV, LDA-sorted)');
xlabel('Trace ID (group + LDA sorted)');
ylabel('Trace ID (group + LDA sorted)');

% === Step 5: 加上 group 分界線 ===
hold on;
group_boundary = sum(labels_sorted == 1);  % USV 組結束的位置
xline(group_boundary + 0.5, 'k--', 'LineWidth', 1.5);  % 垂直分隔線
yline(group_boundary + 0.5, 'k--', 'LineWidth', 1.5);  % 水平分隔線

% === Step 6: 類別色帶 ===
ax_main = gca;
ax_pos = ax_main.Position;
ax_bar = axes('Position', [ax_pos(1), ax_pos(2) + ax_pos(4) + 0.01, ax_pos(3), 0.02]);

classbar = zeros(1, length(labels_sorted));
classbar(labels_sorted == 1) = 1;  % 1 = USV（藍色）, 0 = non-USV（紅色）

imagesc(classbar);
colormap(ax_bar, [1 0 0; 0 0 1]);  % 0 = 紅（non-USV）, 1 = 藍（USV）
set(ax_bar, 'XTick', [], 'YTick', []);
axis tight;
box off;

% === Step 7: 儲存圖檔 ===
saveas(gcf, 'Figure11_PCA_Correlation_Heatmap_GroupThenLDASorted.png');

%% t-SNE with First 10 PCs
tsne_input = score(:,1:10);
tsne_result = tsne(tsne_input);
figure;
gscatter(tsne_result(:,1), tsne_result(:,2), labels, 'rb', 'ox');
title('t-SNE projection using PC1-10');
xlabel('t-SNE 1'); ylabel('t-SNE 2');
saveas(gcf, 'Figure12_tSNE.png');

%% UMAP with First 10 PCs (Requires UMAP toolbox)
try
    [umap_result, ~, ~] = run_umap(tsne_input);
    figure;
    gscatter(umap_result(:,1), umap_result(:,2), labels, 'rb', 'ox');
    title('UMAP projection using PC1-10');
    xlabel('UMAP 1'); ylabel('UMAP 2');
catch
    warning('UMAP toolbox not available or failed to run. Skipping UMAP plot.');
end
saveas(gcf, 'Figure13_UMAP.png');

%% Zip output
files_to_zip = {
    'PCA_Eigenvalue_Table.xlsx', ...
    'Figure1_TracePattern_PCAloadingvsTime.png', ...
    'Figure2_CumulativeVariance.png', ...
    'Figure3_PC_TracePatterns.png', ...
    'Figure4_PC1_PC2_Projection.png', ...
    'Figure5_PCA_LDA_Projection_with_Boundary.png', ...
    'Figure6_ROC_Logistic_PC1to10.png', ...
    'Figure7__Top2_Predictive_TracePatterns_LogReg.png', ...
    'Figure8_Reconstructed_Trace_Top2PC_USVonly.png', ...
    'Figure9_Individual_Reconstructed_Trace_Top2PC_USVonly.png', ...
    'Figure10_LDA_Projection_PC1to10.png', ...
    'Figure11_PCA_Correlation_Heatmap_GroupThenLDASorted.png', ...
    'Figure12_tSNE.png', ...
    'Figure13_UMAP.png'};

zip('PCA_LDA_Logistic_Results_PC1to10.zip', files_to_zip);

